package com.msb.serviceorder.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.msb.commons.constant.CommonStatusEnum;
import com.msb.commons.constant.OrderConstant;
import com.msb.commons.dto.OrderDTO;
import com.msb.commons.dto.OrderInfo;
import com.msb.commons.dto.PriceRule;
import com.msb.commons.response.OrderDriverResponse;
import com.msb.commons.response.ResponseResult;
import com.msb.commons.response.TerminalResponse;
import com.msb.serviceorder.feign.ServiceDriverUserClient;
import com.msb.serviceorder.feign.ServiceMapClient;
import com.msb.serviceorder.feign.ServicePriceClient;
import com.msb.serviceorder.mapper.OrderInfoMapper;
import com.msb.serviceorder.service.OrderInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author chshh
 * @since 2022-11-06
 */
@Service
@Slf4j
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Resource
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private ServicePriceClient servicePriceClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ServiceDriverUserClient serviceDriverUserClient;

    @Autowired
    private ServiceMapClient serviceMapClient;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public ResponseResult add(OrderDTO orderDTO) {

        //判断当前城市是否有可用司机
        ResponseResult<Boolean> result = serviceDriverUserClient.isAvailableDriver(orderDTO.getAddress());
        if (!result.getData()){
            return ResponseResult.fail(CommonStatusEnum.CITY_SERVICE_NOT_DRIVER.getCode(), CommonStatusEnum.CITY_SERVICE_NOT_DRIVER.getValue());
        }

        //判断下单的城市和计价规则是否正常
        if (isPricePuleExists(orderDTO))
            return ResponseResult.fail(CommonStatusEnum.CITY_SERVICE_NOT.getCode(), CommonStatusEnum.CITY_SERVICE_NOT.getValue());

        //需要判断计价规则是否为最新
        ResponseResult<Boolean> aNew = servicePriceClient.isNew(orderDTO.getFareType(), orderDTO.getFareVersion());
        if (!(aNew.getData())){
            return ResponseResult.fail(CommonStatusEnum.PRICE_RULE_EDIT.getCode(),CommonStatusEnum.PRICE_RULE_EDIT.getValue());
        }

        //判断乘客下单的设备是否为黑名单
        if (isBlackDevice(orderDTO))
            return ResponseResult.fail(CommonStatusEnum.DEVICE_IS_BLACK.getCode(), CommonStatusEnum.DEVICE_IS_BLACK.getValue());

        //判断乘客是否有正在进行的订单
        if (isPassengerGoingOrder(orderDTO.getPassengerId())>0){
            return ResponseResult.fail(CommonStatusEnum.ORDER_GOING_ON.getCode(),CommonStatusEnum.ORDER_GOING_ON.getValue());
        }
        //创建订单
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderDTO,orderInfo);
        orderInfo.setOrderStatus(OrderConstant.ORDER_START);
        LocalDateTime now = LocalDateTime.now();
        orderInfo.setGmtCreate(now);
        orderInfo.setGmtModified(now);
        orderInfoMapper.insert(orderInfo);

        //派单
        realTimeDispatchOrder(orderInfo);

        return ResponseResult.success();
    }

    /**
     * 实时订单派单逻辑
     * @param orderInfo
     */
    public void realTimeDispatchOrder(OrderInfo orderInfo){

        //2km
        String depLatitude = orderInfo.getDepLatitude();
        String depLongitude = orderInfo.getDepLongitude();
        String center = depLatitude+","+depLongitude;

        List<Integer> list = new ArrayList<>();
        list.add(2000);
        list.add(4000);
        list.add(5000);
        ResponseResult<ArrayList<TerminalResponse>> listResponseResult = null;
        //goto测试用 后续会修改
        radius:
        for (int i = 0; i <list.size() ; i++) {
            Integer radius = list.get(i);
            listResponseResult = serviceMapClient.aroundsearch(center,radius);

            log.info("在半径为"+radius+"的范围内,寻找车辆,结果: "+ JSONArray.fromObject(listResponseResult.getData()).toString());
            //获得终端
            ArrayList<TerminalResponse> data = listResponseResult.getData();

            //解析终端[{"carId":1562322854910889997,"tid":"597633103"},{"carId":1562322854910889997,"tid":"597633103"}]

            for (int j = 0; j <data.size() ; j++) {
                TerminalResponse terminalResponse = data.get(j);
                Long carId = terminalResponse.getCarId();

                String longitude = terminalResponse.getLongitude();
                String latitude = terminalResponse.getLatitude();
                //根据解析结果查询车辆
                ResponseResult<OrderDriverResponse> availableDriver = serviceDriverUserClient.getAvailableDriver(carId);
                if (availableDriver.getCode() == CommonStatusEnum.AVAILABLE_DRIVER_EMPTY.getCode()){
                    log.info("没有车辆id: "+carId+",对应的司机");
                    continue;
                }else {
                    log.info("车辆id: "+carId+",找到了正在出车的司机");
                    Long driverId = availableDriver.getData().getDriverId();
                    String driverPhone = availableDriver.getData().getDriverPhone();
                    String licenseId = availableDriver.getData().getLicenseId();
                    String vehicleNo = availableDriver.getData().getVehicleNo();

                    //加锁
                    String lockKey = (driverId+"").intern();
                    RLock lock = redissonClient.getLock(lockKey);
                    lock.lock();

                    //判断司机是否有正在进行的订单
                    if (isDriverGoingOrder(driverId)>0){
                        lock.unlock();
                        continue ;
                    }
                    //设置订单中和司机车辆相关的信息
                    orderInfo.setDriverId(driverId);
                    orderInfo.setDriverPhone(driverPhone);
                    orderInfo.setCarId(carId);
                    orderInfo.setLicenseId(licenseId);
                    orderInfo.setVehicleNo(vehicleNo);

                    orderInfo.setReceiveOrderCarLongitude(longitude);
                    orderInfo.setReceiveOrderCarLatitude(latitude);
                    orderInfo.setReceiveOrderTime(LocalDateTime.now());

                    orderInfo.setOrderStatus(OrderConstant.DRIVER_RECEIVE_ORDER);

                    orderInfoMapper.updateById(orderInfo);

                    lock.unlock();
                    //退出,不在进行司机的查找
                    break radius;

                }
            }
        }
    }

    /**
     * 判断下单的城市和计价规则是否正常
     * @param orderDTO
     * @return
     */
    private boolean isPricePuleExists(OrderDTO orderDTO) {
        String fareType = orderDTO.getFareType();
        int index = fareType.indexOf("$");
        String cityCode = fareType.substring(0, index);
        String vehicleType = fareType.substring(index+1);
        PriceRule priceRule = new PriceRule();
        priceRule.setCityCode(cityCode);
        priceRule.setVehicleType(vehicleType);
        ResponseResult<Boolean> result = servicePriceClient.ifExists(priceRule);
        if (!result.getData()){
            return true;
        }
        return false;
    }

    /**
     * 判断乘客下单的设备是否为黑名单
     * @param orderDTO
     * @return
     */
    private boolean isBlackDevice(OrderDTO orderDTO) {
        String deviceCodeKey = "black-device-" + orderDTO.getDeviceCode();
        Boolean aBoolean = stringRedisTemplate.hasKey(deviceCodeKey);
        if (aBoolean){
            String s = stringRedisTemplate.opsForValue().get(deviceCodeKey);
            int i = Integer.parseInt(s);
            if (i>=2){
                return true;
            }else {
                stringRedisTemplate.opsForValue().increment(deviceCodeKey);
            }
        }else{
            stringRedisTemplate.opsForValue().setIfAbsent(deviceCodeKey,"1",1L, TimeUnit.HOURS);
        }
        return false;
    }

    /**
     * 判断乘客是否有正在进行的订单
     * @param passengerId
     * @return =0则显示没有
     */
    private int isPassengerGoingOrder(Long passengerId){
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("passenger_id",passengerId)
                .eq("order_status",OrderConstant.ORDER_START)
                .or().eq("order_status",OrderConstant.DRIVER_RECEIVE_ORDER)
                .or().eq("order_status",OrderConstant.DRIVER_TO_PICK_UP_PASSENGER)
                .or().eq("order_status",OrderConstant.DRIVER_ARRIVED_DEPARTURE)
                .or().eq("order_status",OrderConstant.PICK_UP_PASSENGER)
                .or().eq("order_status",OrderConstant.PASSENGER_GETOFF)
                .or().eq("order_status",OrderConstant.TO_START_PAY);
       return orderInfoMapper.selectCount(wrapper);
    }

    /**
     * 判断司机是否有正在进行的订单
     * @param driverId
     * @return =0则显示没有
     */
    private int isDriverGoingOrder(Long driverId){
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("driver_id",driverId)
                .or().eq("order_status",OrderConstant.DRIVER_RECEIVE_ORDER)
                .or().eq("order_status",OrderConstant.DRIVER_TO_PICK_UP_PASSENGER)
                .or().eq("order_status",OrderConstant.DRIVER_ARRIVED_DEPARTURE)
                .or().eq("order_status",OrderConstant.PICK_UP_PASSENGER);
        return orderInfoMapper.selectCount(wrapper);
    }
}
